﻿using System;
using System.Collections.Generic;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using System.Web.Routing;
using Smarly.Bussines;
using Smarly.Bussines.Membership;
using Smarly.Core;
using Smarly.Web.ActionFilters;
using log4net;

namespace Smarly.Web.Controllers.Base
{
	public static class UrlExtention
	{
		public static string UpdateUrlByParam(this string url, string paramName, string paramValue)
		{
			var indexOf = url.IndexOf("&");
			return url.Substring(0, indexOf > 0 ? indexOf : url.Length) + string.Format("{0}{1}={2}", url.Contains("?") ? "&" : "?", paramName, paramValue);
		}
	}


	public abstract class BaseController : AsyncController
	{
		public delegate void SectionPublishedHandler(HttpRequestBase request);
		public static event SectionPublishedHandler SectionPublished;

		protected void TriggerSectionPublished()
		{
			if (SectionPublished != null)
				SectionPublished(Request);
		}

		protected bool IsAjax { get { return Request.IsAjaxRequest(); } }

		#region Overrides of Controller

		protected override void OnAuthorization(AuthorizationContext filterContext)
		{
			IStatisticAttribute[] attributes = (IStatisticAttribute[]) filterContext.ActionDescriptor.GetCustomAttributes(typeof(IStatisticAttribute), false);
			List<string> updates = attributes.Select(attr => attr.Update(filterContext.RouteData.Values)).ToList();

			filterContext.HttpContext.User = new SmarlyPrincipal(filterContext.HttpContext.Request, filterContext.HttpContext.Response, updates);
			base.OnAuthorization(filterContext);
		}

		protected SmarlyIdentity UserIdentity
		{
			get
			{
				return User.Identity as SmarlyIdentity ?? new SmarlyIdentity(false);
			}
		}


		protected override void Initialize(RequestContext requestContext)
		{
			base.Initialize(requestContext);

			if (requestContext.HttpContext.Request.HttpMethod == "GET")
			{
				string repairParam = Request.Params["repair"];

				if (!string.IsNullOrWhiteSpace(repairParam))
				{
					var modelState = new ModelStateDictionary();
					var up = new Smarly.Bussines.Model.Account.UpdatePassword() { ModelState = modelState, HashCode = repairParam }.GetEmail();
					if (modelState.IsValid)
					{
						ViewBag.RepairEmail = up.Email;
						ViewBag.RepairCode = up.HashCode;
					}
				}
			}

			ViewBag.TextIdPrefix = Global.TextIdPrefix;
			ViewBag.NoteIdPrefix = Global.NoteIdPrefix;
			ViewBag.BookmarkIdPrefix = Global.BookmarkIdPrefix;
			ViewBag.ShareIdPrefix = Global.ShareIdPrefix;
		}

		protected override void OnActionExecuting(ActionExecutingContext filterContext)
		{
			foreach (var modelState in filterContext.ActionParameters.Where(x => x.Value is ModelStateObject).Select(x => x.Value).OfType<ModelStateObject>())
			{
				modelState.ModelState = ModelState;
			}

			base.OnActionExecuting(filterContext);
		}
#if !DEBUG
		private static readonly ILog log = LogManager.GetLogger("Smarly");
#endif

		protected override void OnException(ExceptionContext filterContext)
		{
			var exception = filterContext.Exception;

			if (exception is UnknownPageException)
			{
#if !DEBUG
				var unknownEx = (UnknownPageException) exception;
				unknownEx.Server = Server;
				unknownEx.Request = Request;
				unknownEx.User = User;

				log.Warn("Missing page", unknownEx);
#endif
				filterContext.ExceptionHandled = true;
				filterContext.HttpContext.Response.StatusCode = 404;
				filterContext.Result = RedirectToAction("Index", "Home");
			}
			else
			{
				base.OnException(filterContext);
			}
		}

		#endregion


		#region Render partial

		protected string RenderPartialViewToString()
		{
			return RenderPartialViewToString(null, null);
		}

		protected string RenderPartialViewToString(string viewName)
		{
			return RenderPartialViewToString(viewName, null);
		}

		protected string RenderPartialViewToString(object model)
		{
			return RenderPartialViewToString(null, model);
		}

		protected string RenderPartialViewToString(string viewName, object model)
		{
			if (string.IsNullOrEmpty(viewName))
				viewName = ControllerContext.RouteData.GetRequiredString("action");

			ViewData.Model = model;

			using (StringWriter sw = new StringWriter())
			{
				ViewEngineResult viewResult = ViewEngines.Engines.FindPartialView(ControllerContext, viewName);
				ViewContext viewContext = new ViewContext(ControllerContext, viewResult.View, ViewData, TempData, sw);
				viewResult.View.Render(viewContext, sw);

				return sw.GetStringBuilder().ToString();
			}
		}

		#endregion

		public ActionResult RedirectToActionResult(string actionName, string controllerName, object routeValues)
		{
			return RedirectToAction(actionName, controllerName, routeValues);
		}

		protected JsonResult JsonValidationErrors()
		{
			var enumerable = ModelState
				.Where(x => x.Value.Errors.Count > 0)
				.Select(x => new
											{
												element = x.Key,
												errorTitle = "Вниминие!",
												errorMessage = x.Value.Errors.First().ErrorMessage
											}).ToList();

			return Json(new { errors = enumerable.Any() ? enumerable : null });
		}

		protected void Message(Message message, params string[] parameters)
		{
			const string deliver = "`";
			string value = ((int)message).ToString(CultureInfo.InvariantCulture) + deliver;
			if (parameters != null)
			{
				value = parameters.Aggregate(value, (current, p) => current + (Server.UrlEncode(p) + deliver));
			}
			Response.Cookies.Add(new HttpCookie("message", value.TrimEnd('`')));
		}

		protected void ShareLabel(string url, string shareId)
		{
			Response.Cookies.Add(new HttpCookie("share", shareId)
				                     {
															 Domain = Request.AuthDomain(),
															 Expires = DateTime.UtcNow.AddYears(1),
															 Path = url
				                     });

			Response.Cookies.Add(new HttpCookie("share_value", shareId)
				                     {
															 Domain = Request.AuthDomain(),
															 Path = url
				                     });
		}

		protected string GetShareLabel(bool clear, string url)
		{
			var cookie = Request.Cookies["share_value"];

			if (clear && cookie != null)
			{
				cookie.Expires = new DateTime(1900, 1, 1);
				cookie.Domain = Request.AuthDomain();
				cookie.Path = url;
				Response.Cookies.Add(cookie);
			}

			return cookie != null ? cookie.Value : null;
		}
	}
}
